/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "OsIf.h"
#include "arm_mpu.h"
#include "lnk_mpu.h"
#include "e3_device.h"

#if !defined(E3650_LP)

#if defined(CFG_XIP)
#define  MPU_CONST_ADDR_START   FLASH_CONST_START
#define  MPU_CONST_ADDR_END     FLASH_CONST_END
#define  MPU_TEXT_ADDR_START    FLASH_TEXT_START
#define  MPU_TEXT_ADDR_END      FLASH_TEXT_END
#define  MPU_IRAM_FUNC_START    FLASH_FUNC_INIT_START
#define  MPU_IRAM_FUNC_END      FLASH_FUNC_INIT_END
#else
#define  MPU_CONST_ADDR_START   IRAM_CONST_START
#define  MPU_CONST_ADDR_END     IRAM_CONST_END
#define  MPU_TEXT_ADDR_START    IRAM_TEXT_START
#define  MPU_TEXT_ADDR_END      IRAM_TEXT_END
#define  MPU_IRAM_FUNC_START    IRAM_FUNC_INIT_START
#define  MPU_IRAM_FUNC_END      IRAM_FUNC_INIT_END
#endif

static const Mpu_ConfigType Comm_regionCfg[] =
{
    {
        .region = 0U,
        .startAddr = (uint32)CRAM_TEXT_START,
        .limitAddr = (uint32)CRAM_TEXT_END - 0x3FUL,
        .type = MPU_REGION_READONLY,
    },
    /* Iram Function code section */
    {
        .region = 1U,
        .startAddr = (uint32)IRAM_FUNC_START,
        .limitAddr = (uint32)IRAM_FUNC_END - 0x3FUL,
        .type = MPU_REGION_READONLY,
    },
    /* Nocache rw data section */
    {
        .region = 2U,
        .startAddr = (uint32)IRAM_NOCACHE_START,
        .limitAddr = (uint32)IRAM_NOCACHE_END - 0x3FUL,
        .type = MPU_REGION_NORMAL_NONCACHEABLE,
    },
    /* RW DATA+BSS section */
    {
        .region = 3U,
        .startAddr = (uint32)IRAM_DATA_START,
        .limitAddr = (uint32)IRAM_BSS_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    },
    /* Iram text code section */
    {
        .region = 4U,
        .startAddr = (uint32)MPU_TEXT_ADDR_START,
        .limitAddr = (uint32)MPU_TEXT_ADDR_END - 0x3FUL,
        .type = MPU_REGION_READONLY,
    },
    /* Ro Sec Code + Const + DataInited + iarm func  code section */
    {
        .region = 5U,
        .startAddr = (uint32)MPU_CONST_ADDR_START,
        .limitAddr = (uint32)MPU_IRAM_FUNC_END - 0x3FUL,
        .type = MPU_REGION_READONLY_XN,
    },
    /* Register space */
    {
        .region = 6U,
        .startAddr = (uint32)0xF0000000UL,
        .limitAddr = (uint32)0xFFFFFFFFUL - 0x3FUL,
        .type = MPU_REGION_NGNRE,
    },
    /* IRAM_LP */
    {
        .region = 7U,
        .startAddr = (uint32)IRAM_LP_START,
        .limitAddr = (uint32)IRAM_LP_END - 0x3FUL,
        .type = MPU_REGION_READONLY,
    },
};

static const Mpu_ConfigType Core0_regionCfg[] =
{
    /* TCM A/B/C section, using for core stack */
    {
        .region = 10U,
        .startAddr = (uint32)CORE0TCMC_START,
        .limitAddr = (uint32)CORE0TCMC_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    }

};
static const Mpu_ConfigType Core1_regionCfg[] =
{
    /* TCM A/B/C section, using for core stack */
    {
        .region = 10U,
        .startAddr = (uint32)CORE1TCMC_START,
        .limitAddr = (uint32)CORE1TCMC_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    }

};
static const Mpu_ConfigType Core2_regionCfg[] =
{
    /* TCM A/B/C section, using for core stack */
    {
        .region = 10U,
        .startAddr = (uint32)CORE2TCMC_START,
        .limitAddr = (uint32)CORE2TCMC_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    }

};
static const Mpu_ConfigType Core3_regionCfg[] =
{
    /* TCM A/B/C section, using for core stack */
    {
        .region = 10U,
        .startAddr = (uint32)CORE3TCMC_START,
        .limitAddr = (uint32)CORE3TCMC_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    }

};
#if defined(MRAM_TEST)
/*
    Note: It is not recommended to grant write permission to MRAM unless absolutely necessary.
This only for mram test
*/
static const Mpu_ConfigType Mram_regionCfg[] =
{
    /* mram bankB f port space ro nx  */
    {
        .region = 11U,
        .startAddr = (uint32)FLASH_RESERVED_B_START,
        .limitAddr = (uint32)FLASH_RESERVED_B_END - 0x3FUL,
        .type = MPU_REGION_READONLY_XN,
    },
    /* mram bankB m port space wr nx  */
    {
        .region = 12U,
        .startAddr = (uint32)MPU_F_TO_M_ADDR(FLASH_RESERVED_B_START),
        .limitAddr = (uint32)MPU_F_TO_M_ADDR(FLASH_RESERVED_B_END) - 0x3FUL,
        .type = MPU_REGION_RW_CACHEABLE_XN,
    },
    /* mram5 f port space ro nx  */
    {
        .region = 13U,
        .startAddr = (uint32)FLASH_DFLASH_START,
        .limitAddr = (uint32)FLASH_DFLASH_END - 0x3FUL,
        .type = MPU_REGION_READONLY_XN,
    },
    /* mram5 m port space wr nx  */
    {
        .region = 14U,
        .startAddr = (uint32)MPU_F_TO_M_ADDR(FLASH_DFLASH_START),
        .limitAddr = (uint32)MPU_F_TO_M_ADDR(FLASH_DFLASH_END) - 0x3FUL,
        .type = MPU_REGION_RW_CACHEABLE_XN,
    }
};
#endif /* Mram test env need */

#if defined(FLS_TEST)
/*
    This only for Fls test
*/
static const Mpu_ConfigType Fls_regionCfg[] =
{
    /* Fls XSPI1A f port space  */
    {
        .region = 15U,
        .startAddr = (uint32)FLASH_NORFLASH_START,
        .limitAddr = (uint32)FLASH_NORFLASH_END - 0x3FUL,
        .type = MPU_REGION_NORMAL,
    },
};
#endif /* Fls test env need */

void Mpu_init(void)
{
    uint8 coreId = Mcal_GetCpuIndex();
    unsigned int mpu_init_ret = 0;
    Mpu_enable(FALSE);
    Mpu_reset();

    mpu_init_ret |= Mpu_Config(Comm_regionCfg, (sizeof(Comm_regionCfg) / sizeof(Comm_regionCfg[0U])));

    if(CPU_INDEX_0 == coreId)
    {
        mpu_init_ret |= Mpu_Config(Core0_regionCfg, (sizeof(Core0_regionCfg) / sizeof(Core0_regionCfg[0U])));
    }
    else if (CPU_INDEX_1 == coreId)
    {
        mpu_init_ret |= Mpu_Config(Core1_regionCfg, (sizeof(Core1_regionCfg) / sizeof(Core1_regionCfg[0U])));
    }
    else if (CPU_INDEX_2 == coreId)
    {
        mpu_init_ret |= Mpu_Config(Core2_regionCfg, (sizeof(Core2_regionCfg) / sizeof(Core2_regionCfg[0U])));
    }
    else if (CPU_INDEX_3 == coreId)
    {
        mpu_init_ret |= Mpu_Config(Core3_regionCfg, (sizeof(Core3_regionCfg) / sizeof(Core3_regionCfg[0U])));
    }else {
        /* do nothing */
    }
#if defined(MRAM_TEST)
    /* this ragions only for mram test */
    mpu_init_ret |= Mpu_Config(Mram_regionCfg, (sizeof(Mram_regionCfg) / sizeof(Mram_regionCfg[0U])));
#endif
#if defined(FLS_TEST)
    /* this ragions only for mram test */
    mpu_init_ret |= Mpu_Config(Fls_regionCfg, (sizeof(Fls_regionCfg) / sizeof(Fls_regionCfg[0U])));
#endif
    if(0u  == mpu_init_ret){
        Mpu_enable(TRUE);
    }
    else
    {
        while(1);
    }

}
#endif

